#include "scheduler.h"
#include "marco.h"
#include "hook.h"

static thread_local Scheduler* t_scheduler = nullptr; //协程调度器的指针
static thread_local Fiber* t_scheduler_fiber = nullptr; //当前协程的主协程

Scheduler::Scheduler(size_t threads, bool use_caller, const std::string& name)
    : m_name(name){
    SYLAR_ASSERT(threads > 0);

    if(use_caller) {
        Fiber::GetThis(); //创建一个主协程
        --threads;

        SYLAR_ASSERT(GetThis() == nullptr);
        t_scheduler = this;

        m_rootFiber.reset(new Fiber(std::bind(&Scheduler::run, this), 0, true));
        Thread::SetName(m_name);

        t_scheduler_fiber = m_rootFiber.get();
        m_rootThread = sylar::GetThreadId(); //保存主线程id
        m_threadIds.push_back(m_rootThread); //添加到线程组
    } else {
        m_rootThread = -1;
    }
    m_threadCount = threads;
}

Scheduler::~Scheduler() { //释放调度器
    SYLAR_ASSERT(m_stopping);
    if(GetThis() == this) {
        t_scheduler = nullptr;
    }
}

Scheduler* Scheduler::GetThis() { //返回协程调度器
    return t_scheduler;
}

Fiber* Scheduler::GetMainFiber() { //返回主协程
    return t_scheduler_fiber;
}

void Scheduler::start() {   //线程池启动
    MutexType::Lock lock(m_mutex);
    if(!m_stopping) {
        return;
    }
    m_stopping = false;
    SYLAR_ASSERT(m_threads.empty()); //如果不为空就返回

    m_threads.resize(m_threadCount); //重新设置线程数量
    for(size_t i = 0; i < m_threadCount; ++i) { //创建线程
        m_threads[i].reset(new Thread(std::bind(&Scheduler::run, this) //线程执行方法
                            , m_name + "_" + std::to_string(i)));
        m_threadIds.push_back(m_threads[i]->getThreadId());
    }
    lock.unlock();

    //if(m_rootFiber) {
    //    //m_rootFiber->swapIn();
    //    m_rootFiber->call();
    //    SYLAR_LOG_INFO(g_logger) << "call out " << m_rootFiber->getState();
    //}
}

void Scheduler::stop() {
    m_autoStop = true;
    if(m_rootFiber
            && m_threadCount == 0
            && (m_rootFiber->getState() == Fiber::TERM
                || m_rootFiber->getState() == Fiber::INIT)) {//判断协程的状态
        std::cout << this << " stopped" << std::endl;
        m_stopping = true;

        if(stopping()) {
            return;
        }
    }

    //bool exit_on_this_fiber = false;
    if(m_rootThread != -1) {
        SYLAR_ASSERT(GetThis() == this);
    } else {
        SYLAR_ASSERT(GetThis() != this);
    }

    m_stopping = true;
    for(size_t i = 0; i < m_threadCount; ++i) {
        tickle();
    }

    if(m_rootFiber) {
        tickle();
    }

    if(m_rootFiber) {
        //while(!stopping()) {
        //    if(m_rootFiber->getState() == Fiber::TERM
        //            || m_rootFiber->getState() == Fiber::EXCEPT) {
        //        m_rootFiber.reset(new Fiber(std::bind(&Scheduler::run, this), 0, true));
        //        SYLAR_LOG_INFO(g_logger) << " root fiber is term, reset";
        //        t_fiber = m_rootFiber.get();
        //    }
        //    m_rootFiber->call();
        //}
        if(!stopping()) {
            m_rootFiber->call();
        }
    }

    std::vector<Thread::ptr> thrs;
    {
        MutexType::Lock lock(m_mutex);
        thrs.swap(m_threads);
    }

    for(auto& i : thrs) {
        i->join();
    }
    //if(exit_on_this_fiber) {
    //}
}

void Scheduler::setThis() {
    t_scheduler = this;
}

//线程调度的主函数
void Scheduler::run() {//执行线程
    std::cout << m_name << " run" << std::endl;
    sylar::set_hook_enable(true);
    setThis(); //线程进来，设置调度器为线程本身
    if(sylar::GetThreadId() != m_rootThread) { //如果线程id不为主线程id
        t_scheduler_fiber = Fiber::GetThis().get(); //把线程主协程设为当前的主协程
    }

    Fiber::ptr idle_fiber(new Fiber(std::bind(&Scheduler::idle, this)));//没有任务之后退出所有协程
    Fiber::ptr cb_fiber;

    FiberAndThread ft;
    while(true) {
        ft.reset();
        bool tickle_me = false;
        bool is_active = false;
        {
            MutexType::Lock lock(m_mutex);
            auto it = m_fibers.begin();
            while(it != m_fibers.end()) {
                //如果任务指定了线程执行，但是正在执行的线程与他不同，直接跳过
                if(it->thread != -1 && it->thread != sylar::GetThreadId()) {
                    ++it;
                    tickle_me = true;
                    continue;
                }

                SYLAR_ASSERT(it->fiber || it->cb);
                if(it->fiber && it->fiber->getState() == Fiber::EXEC) {//调用的协程正在执行 跳过处理
                    ++it;
                    continue;
                }

                ft = *it; //把协程拿出来处理
                m_fibers.erase(it++);  //并且把协程数组中对应的协程删除
                ++m_activeThreadCount; //忙线程数量加一
                is_active = true;
                break;
            }
            tickle_me |= it != m_fibers.end();
        }

        if(tickle_me) {
            tickle(); //唤醒线程
        }
        //协程方式
        if(ft.fiber && (ft.fiber->getState() != Fiber::TERM 
                        && ft.fiber->getState() != Fiber::EXCEPT)) {
            ft.fiber->swapIn(); //切换到当且协程执行
            --m_activeThreadCount;

            if(ft.fiber->getState() == Fiber::READY) {//如在还在读状态
                schedule(ft.fiber); //继续调度该协程执行
            } else if(ft.fiber->getState() != Fiber::TERM //如果不等于TERM EXCEPT这两个结束装填
                    && ft.fiber->getState() != Fiber::EXCEPT) {
                ft.fiber->m_state = Fiber::HOLD;  //把状态设置为HOLD
            }
            ft.reset(); //重置调度器
        } else if(ft.cb) { //回调函数的方式
            if(cb_fiber) { //如果不为空
                cb_fiber->reset(ft.cb); //设置上下文
            } else {    //如果为空
                cb_fiber.reset(new Fiber(ft.cb)); //创建一个Fiber
            }
            ft.reset(); //重置(释放)
            cb_fiber->swapIn(); //切换到当前协程
            --m_activeThreadCount;
            if(cb_fiber->getState() == Fiber::READY) { //当前协程为读
                schedule(cb_fiber); //重新调度
                cb_fiber.reset(); //重置
            } else if(cb_fiber->getState() == Fiber::EXCEPT //结束状态
                    || cb_fiber->getState() == Fiber::TERM) {
                cb_fiber->reset(nullptr);   //直接重置(释放)
            } else {//if(cb_fiber->getState() != Fiber::TERM) { 没有结束
                cb_fiber->m_state = Fiber::HOLD; //状态改为暂停
                cb_fiber.reset(); //重置
            }
        } else {
            if(is_active) {
                --m_activeThreadCount;
                continue;
            }
            //所有任务执行完成，执行idle_fiber协程
            if(idle_fiber->getState() == Fiber::TERM) { //如果为结束状态
                std::cout << "idle fiber term" << std::endl;
                break;
            }

            ++m_idleThreadCount; //空闲线程加1
            idle_fiber->swapIn();  //切换到当前协程
            --m_idleThreadCount;
            if(idle_fiber->getState() != Fiber::TERM //不为结束状态
                    && idle_fiber->getState() != Fiber::EXCEPT) {
                idle_fiber->m_state = Fiber::HOLD;  //设为hold状态
            }
        }
    }

}

void Scheduler::tickle() {
    std::cout << "tickle" << std::endl;
}

bool Scheduler::stopping() {
    MutexType::Lock lock(m_mutex);
    return m_autoStop && m_stopping
        && m_fibers.empty() && m_activeThreadCount == 0;
}

void Scheduler::idle() {
    std::cout << "idle" << std::endl;
    while(!stopping()) {
        Fiber::YieldToHold();
    }
}
